package com.pcbly.web.components.license.io;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;

import org.apache.log4j.Logger;
import org.apache.commons.codec.binary.Base64;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.pcbly.web.components.license.License;
import com.pcbly.web.components.license.LicenseException;
import com.pcbly.web.components.license.validator.CheckSignatureValidator;
import com.pcbly.web.components.license.validator.Validator;

public class LicenseReader {
	private static final Logger log = Logger.getLogger(LicenseReader.class);

	public License read(Reader reader) throws LicenseException, IOException {
		License license=new License();
		String xml = decodeToXml(reader);
		return license.fromXML(xml);
	}

	public License read(String encryptedLicenseKey) throws LicenseException,
			IOException {
		StringReader reader = new StringReader(encryptedLicenseKey);
		return read(((Reader) (reader)));
	}

	public String formatLicense(String encryptedLicenseKey,
			boolean checkSignature) throws LicenseException, IOException {
		StringReader reader = new StringReader(encryptedLicenseKey);
		String xml = decodeToXml(reader);
		License license=new License();
		if (checkSignature) { 
			Validator validator = new CheckSignatureValidator();
			validator.validate(license.fromXML(xml));
		}
		return prettyPrintLicense(xml);
	}

	public String formatLicense(String encryptedLicenseKey)
			throws LicenseException, IOException {
		return formatLicense(encryptedLicenseKey, false);
	}

	public String prettyPrintLicense(String decryptedLicenseKey)
			throws LicenseException {
		try {
			StringWriter writer;
			StringReader reader = new StringReader(decryptedLicenseKey);
			org.dom4j.Document doc = (new SAXReader()).read(reader);
			reader.close();
			OutputFormat outputFormat = OutputFormat.createPrettyPrint();
			outputFormat.setNewlines(true);
			outputFormat.setTrimText(false);
			writer = new StringWriter();
			XMLWriter xmlWriter = new XMLWriter(writer, outputFormat);
			xmlWriter.write(doc);
			writer.close();
			return writer.toString();
		} catch (Exception e) {
			throw new LicenseException(e);
		}
	}

	private String decodeToXml(Reader in) throws IOException {
		StringBuffer text = new StringBuffer();
		char buf[] = new char[1024];
		int len;
		while ((len = in.read(buf)) >= 0) {
			int j = 0;
			while (j < len) {
				char ch = buf[j];
				if (Character.isLetter(ch) || Character.isDigit(ch)
						|| ch == '+' || ch == '/' || ch == '=')
					text.append(ch);
				j++;
			}
		}
		in.close();
		String xml = new String(Base64.decodeBase64(text.toString().getBytes(
				"utf-8")));
		if (!text.toString().matches("^[^\\s]*$")) {
			throw new AssertionError();
		} else {
			log.debug(xml);
			return xml;
		}
	}

}
